home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / plug-ins / imagemap / imap_main.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-07-20  |  33.8 KB  |  1,454 lines

  1. /*
  2.  * This is a plug-in for the GIMP.
  3.  *
  4.  * Generates clickable image maps.
  5.  *
  6.  * Copyright (C) 1998-1999 Maurits Rijk  lpeek.mrijk@consunet.nl
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License as published by
  10.  * the Free Software Foundation; either version 2 of the License, or
  11.  * (at your option) any later version.
  12.  *
  13.  * This program is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  * GNU General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU General Public License
  19.  * along with this program; if not, write to the Free Software
  20.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21.  *
  22.  */
  23.  
  24. #include "config.h"
  25.  
  26. #include <stdarg.h>
  27. #include <stdlib.h>
  28. #include <stdio.h>
  29. #include <string.h>
  30.  
  31. #include <gtk/gtk.h>
  32. #include <gdk/gdkkeysyms.h> /* for keyboard values */
  33.  
  34. #include <libgimp/gimp.h>
  35. #include <libgimp/gimpui.h>
  36.  
  37. #include "imap_about.h"
  38. #include "imap_circle.h"
  39. #include "imap_cmd_clear.h"
  40. #include "imap_cmd_copy.h"
  41. #include "imap_cmd_cut.h"
  42. #include "imap_cmd_create.h"
  43. #include "imap_cmd_guides.h"
  44. #include "imap_cmd_move.h"
  45. #include "imap_cmd_move_down.h"
  46. #include "imap_cmd_move_sash.h"
  47. #include "imap_cmd_move_selected.h"
  48. #include "imap_cmd_move_to_front.h"
  49. #include "imap_cmd_move_up.h"
  50. #include "imap_cmd_object_move.h"
  51. #include "imap_cmd_paste.h"
  52. #include "imap_cmd_select.h"
  53. #include "imap_cmd_select_all.h"
  54. #include "imap_cmd_select_next.h"
  55. #include "imap_cmd_select_prev.h"
  56. #include "imap_cmd_select_region.h"
  57. #include "imap_cmd_send_to_back.h"
  58. #include "imap_cmd_unselect.h"
  59. #include "imap_cmd_unselect_all.h"
  60. #include "imap_default_dialog.h"
  61. #include "imap_edit_area_info.h"
  62. #include "imap_file.h"
  63. #include "imap_grid.h"
  64. #include "imap_main.h"
  65. #include "imap_menu.h"
  66. #include "imap_object.h"
  67. #include "imap_polygon.h"
  68. #include "imap_popup.h"
  69. #include "imap_preview.h"
  70. #include "imap_rectangle.h"
  71. #include "imap_selection.h"
  72. #include "imap_settings.h"
  73. #include "imap_source.h"
  74. #include "imap_statusbar.h"
  75. #include "imap_string.h"
  76. #include "imap_toolbar.h"
  77. #include "imap_tools.h"
  78.  
  79. #include "libgimp/stdplugins-intl.h"
  80.  
  81.  
  82. #define MAX_ZOOM_FACTOR 8
  83. #define ZOOMED(x) (_zoom_factor * (x))
  84. #define GET_REAL_COORD(x) ((x) / _zoom_factor)
  85.  
  86. /* Global variables */
  87. static MapInfo_t   _map_info;
  88. static PreferencesData_t _preferences = {CSIM, TRUE, FALSE, TRUE, TRUE, FALSE,
  89. FALSE, DEFAULT_UNDO_LEVELS, DEFAULT_MRU_SIZE};
  90. static MRU_t *_mru;
  91.  
  92. static GdkCursorType _cursor;
  93. static gboolean        _show_url = TRUE;
  94. static gchar       *_filename = NULL;
  95. static char       *_image_name;
  96. static gint       _image_width;
  97. static gint       _image_height;
  98. static GtkWidget   *_dlg;
  99. static Preview_t   *_preview;
  100. static Selection_t *_selection;
  101. static StatusBar_t *_statusbar;
  102. static ToolBar_t   *_toolbar;
  103. static ObjectList_t *_shapes;
  104. static gint        _zoom_factor = 1;
  105. static void (*_button_press_func)(GtkWidget*, GdkEventButton*, gpointer);
  106. static gpointer _button_press_param;
  107.  
  108. /* Declare local functions. */
  109. static void query (void);
  110. static void run (char *name,
  111.          int nparams,
  112.          GimpParam * param,
  113.          int *nreturn_vals,
  114.          GimpParam ** return_vals);
  115. static gint dialog(GimpDrawable *drawable);
  116.  
  117. GimpPlugInInfo PLUG_IN_INFO = {
  118.    NULL,            /* init_proc */
  119.    NULL,            /* quit_proc */
  120.    query,            /* query_proc */
  121.    run,                /* run_proc */
  122. };
  123.  
  124. static int run_flag = 0;
  125.  
  126.  
  127. MAIN ()
  128.  
  129. static void query()
  130. {
  131.    static GimpParamDef args[] = {
  132.       {GIMP_PDB_INT32, "run_mode", "Interactive"},
  133.       {GIMP_PDB_IMAGE, "image", "Input image (unused)"},
  134.       {GIMP_PDB_DRAWABLE, "drawable", "Input drawable"},
  135.    };
  136.    static GimpParamDef *return_vals = NULL;
  137.    static int nargs = sizeof (args) / sizeof (args[0]);
  138.    static int nreturn_vals = 0;
  139.    
  140.    gimp_install_procedure("plug_in_imagemap",
  141.               "Creates a clickable imagemap.",
  142.               "",
  143.               "Maurits Rijk",
  144.               "Maurits Rijk",
  145.               "1998-1999",
  146.               N_("<Image>/Filters/Web/ImageMap..."),
  147.               "RGB*, GRAY*, INDEXED*",
  148.               GIMP_PLUGIN,
  149.               nargs, nreturn_vals,
  150.               args, return_vals);
  151. }
  152.  
  153. static void
  154. run(char *name, int n_params, GimpParam *param, int *nreturn_vals,
  155.     GimpParam **return_vals)
  156. {
  157.    static GimpParam values[1];
  158.    GimpDrawable *drawable;
  159.    GimpRunModeType run_mode;
  160.    GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  161.  
  162.    INIT_I18N_UI();
  163.  
  164.    *nreturn_vals = 1;
  165.    *return_vals = values;
  166.    
  167.    /*  Get the specified drawable  */
  168.    drawable = gimp_drawable_get(param[2].data.d_drawable);
  169.    _image_name = gimp_image_get_filename(param[1].data.d_image);
  170.    _image_width = gimp_image_width(param[1].data.d_image);
  171.    _image_height = gimp_image_height(param[1].data.d_image);
  172.  
  173.    _map_info.color = gimp_drawable_is_rgb(drawable->id);
  174.  
  175.    run_mode = (GimpRunModeType) param[0].data.d_int32;
  176.    
  177.    if (run_mode == GIMP_RUN_INTERACTIVE) {
  178.       if (!dialog(drawable)) {
  179.      /* The dialog was closed, or something similarly evil happened. */
  180.      status = GIMP_PDB_EXECUTION_ERROR;
  181.       }
  182.    }
  183.       
  184.    if (status == GIMP_PDB_SUCCESS) {
  185.       gimp_drawable_detach(drawable);
  186.    }
  187.    
  188.    values[0].type = GIMP_PDB_STATUS;
  189.    values[0].data.d_status = status;
  190. }
  191.  
  192. MRU_t*
  193. get_mru(void)
  194. {
  195.    if (!_mru)
  196.       _mru = mru_create();
  197.    return _mru;
  198. }
  199.  
  200. MapInfo_t*
  201. get_map_info(void)
  202. {
  203.    return &_map_info;
  204. }
  205.  
  206. PreferencesData_t*
  207. get_preferences(void)
  208. {
  209.    return &_preferences;
  210. }
  211.  
  212. static void
  213. init_preferences(void)
  214. {
  215.    GdkColormap *colormap = gdk_window_get_colormap(_dlg->window);
  216.    ColorSelData_t *colors = &_preferences.colors;
  217.  
  218.    colors->normal_fg.red = 0;
  219.    colors->normal_fg.green = 0xFFFF;
  220.    colors->normal_fg.blue = 0;
  221.    
  222.    colors->normal_bg.red = 0;
  223.    colors->normal_bg.green = 0;
  224.    colors->normal_bg.blue = 0xFFFF;
  225.    
  226.    colors->selected_fg.red = 0xFFFF;
  227.    colors->selected_fg.green = 0;
  228.    colors->selected_fg.blue = 0;
  229.    
  230.    colors->selected_bg.red = 0;
  231.    colors->selected_bg.green = 0;
  232.    colors->selected_bg.blue = 0xFFFF;
  233.    
  234.    preferences_load(&_preferences);
  235.  
  236.    gdk_color_alloc(colormap, &colors->normal_fg);
  237.    gdk_color_alloc(colormap, &colors->normal_bg);
  238.    gdk_color_alloc(colormap, &colors->selected_fg);
  239.    gdk_color_alloc(colormap, &colors->selected_bg);
  240.  
  241.    _preferences.normal_gc = gdk_gc_new(_preview->preview->window);
  242.    _preferences.selected_gc = gdk_gc_new(_preview->preview->window);
  243.  
  244.    gdk_gc_set_line_attributes(_preferences.normal_gc, 1, GDK_LINE_DOUBLE_DASH,
  245.                   GDK_CAP_BUTT, GDK_JOIN_BEVEL);
  246.    gdk_gc_set_line_attributes(_preferences.selected_gc, 1, 
  247.                   GDK_LINE_DOUBLE_DASH, GDK_CAP_BUTT, 
  248.                   GDK_JOIN_BEVEL);
  249.    
  250.    gdk_gc_set_foreground(_preferences.normal_gc, &colors->normal_fg);
  251.    gdk_gc_set_background(_preferences.normal_gc, &colors->normal_bg);
  252.    gdk_gc_set_foreground(_preferences.selected_gc, &colors->selected_fg);
  253.    gdk_gc_set_background(_preferences.selected_gc, &colors->selected_bg);
  254.  
  255.    mru_set_size(_mru, _preferences.mru_size);
  256.    command_list_set_undo_level(_preferences.undo_levels);
  257. }
  258.  
  259.  
  260. gint
  261. get_image_width(void)
  262. {
  263.    return _image_width;
  264. }
  265.  
  266. gint
  267. get_image_height(void)
  268. {
  269.    return _image_height;
  270. }
  271.  
  272. void 
  273. set_busy_cursor(void)
  274. {
  275.    preview_set_cursor(_preview, GDK_WATCH);
  276. }
  277.  
  278. void 
  279. remove_busy_cursor(void)
  280. {
  281.    gdk_window_set_cursor(_dlg->window, NULL);
  282. }
  283.  
  284. static gint
  285. zoom_in(void)
  286. {
  287.    if (_zoom_factor < MAX_ZOOM_FACTOR) {
  288.       set_zoom(_zoom_factor + 1);
  289.       menu_set_zoom(_zoom_factor);
  290.    }
  291.    return _zoom_factor;
  292. }
  293.  
  294. static gint
  295. zoom_out(void)
  296. {
  297.    if (_zoom_factor > 1) {
  298.       set_zoom(_zoom_factor - 1);
  299.       menu_set_zoom(_zoom_factor);
  300.    }
  301.    return _zoom_factor;
  302. }
  303.  
  304. void
  305. set_zoom(gint zoom_factor)
  306. {
  307.    set_busy_cursor();
  308.    _zoom_factor = zoom_factor;
  309.    toolbar_set_zoom_sensitivity(_toolbar, zoom_factor);
  310.    preview_zoom(_preview, zoom_factor);
  311.    statusbar_set_zoom(_statusbar, zoom_factor);
  312.    remove_busy_cursor();
  313. }
  314.  
  315. void
  316. main_toolbar_set_grid(gboolean active)
  317. {
  318.    toolbar_set_grid(_toolbar, active);
  319. }
  320.  
  321. gint
  322. get_real_coord(gint coord)
  323. {
  324.    return GET_REAL_COORD(coord);
  325. }
  326.  
  327. void
  328. draw_line(GdkWindow *window, GdkGC *gc, gint x1, gint y1, gint x2, gint y2)
  329. {
  330.    gdk_draw_line(window, gc, ZOOMED(x1), ZOOMED(y1), ZOOMED(x2), ZOOMED(y2));
  331. }
  332.  
  333. void
  334. draw_rectangle(GdkWindow *window, GdkGC    *gc, gint filled, gint x, gint y,
  335.            gint width, gint    height)
  336. {
  337.    gdk_draw_rectangle(window, gc, filled, ZOOMED(x), ZOOMED(y),
  338.               ZOOMED(width), ZOOMED(height));
  339. }
  340.  
  341. void
  342. draw_arc(GdkWindow *window, GdkGC *gc, gint filled, gint x, gint y,
  343.      gint width, gint height, gint angle1, gint angle2)
  344. {
  345.    gdk_draw_arc(window, gc, filled, ZOOMED(x), ZOOMED(y),
  346.         ZOOMED(width), ZOOMED(height), angle1, angle2);
  347. }
  348.  
  349. void
  350. draw_circle(GdkWindow *window, GdkGC *gc, gint filled, gint x, gint y, gint r)
  351. {
  352.    draw_arc(window, gc, filled, x - r, y - r, 2 * r, 2 * r, 0, 360 * 64);
  353. }
  354.  
  355. void
  356. draw_polygon(GdkWindow *window, GdkGC *gc, GList *list)
  357. {
  358.    gint       npoints = g_list_length(list);
  359.    GdkPoint  *points = g_new(GdkPoint, npoints);
  360.    GdkPoint  *des = points;
  361.    GList     *p;
  362.  
  363.    for (p = list; p; p = p->next, des++) {
  364.       GdkPoint *src = (GdkPoint*) p->data;
  365.       des->x = ZOOMED(src->x);
  366.       des->y = ZOOMED(src->y);
  367.    }
  368.    gdk_draw_polygon(window, gc, FALSE, points, npoints);
  369.    g_free(points);
  370. }
  371.  
  372. static gboolean _preview_redraw_blocked = FALSE;
  373. static gboolean _pending_redraw = FALSE;
  374.  
  375. void
  376. preview_freeze(void)
  377. {
  378.    _preview_redraw_blocked = TRUE;
  379. }
  380.  
  381. void
  382. preview_thaw(void)
  383. {
  384.    _preview_redraw_blocked = FALSE;
  385.    if (_pending_redraw) {
  386.       _pending_redraw = FALSE;
  387.       redraw_preview();
  388.    }
  389. }
  390.  
  391. void 
  392. redraw_preview(void)
  393. {
  394.    if (_preview_redraw_blocked)
  395.       _pending_redraw = TRUE;
  396.    else
  397.       preview_redraw(_preview);
  398. }
  399.  
  400. static void
  401. set_preview_gray(void)
  402. {
  403.    _map_info.show_gray = TRUE;
  404.    set_zoom(_zoom_factor);
  405. }
  406.  
  407. static void
  408. set_preview_color(void)
  409. {
  410.    _map_info.show_gray = FALSE;
  411.    set_zoom(_zoom_factor);
  412. }
  413.  
  414. const char*
  415. get_image_name(void)
  416. {
  417.    return _image_name;
  418. }
  419.  
  420. const char*
  421. get_filename(void)
  422. {
  423.    return _filename;
  424. }
  425.  
  426. void
  427. set_arrow_func(void)
  428. {
  429.    _button_press_func = arrow_on_button_press;
  430.    _cursor = GDK_TOP_LEFT_ARROW;
  431. }
  432.  
  433. static void 
  434. set_object_func(void (*func)(GtkWidget*, GdkEventButton*, 
  435.                  gpointer), gpointer param)
  436. {
  437.    _button_press_func = func;
  438.    _button_press_param = param;
  439.    _cursor = GDK_CROSSHAIR;
  440. }
  441.  
  442. void
  443. set_rectangle_func(void)
  444. {
  445.    set_object_func(object_on_button_press, get_rectangle_factory);
  446. }
  447.  
  448. void
  449. set_circle_func(void)
  450. {
  451.    set_object_func(object_on_button_press, get_circle_factory);
  452. }
  453.  
  454. void
  455. set_polygon_func(void)
  456. {
  457.    set_object_func(object_on_button_press, get_polygon_factory);
  458. }
  459.  
  460. void
  461. add_shape(Object_t *obj)
  462. {
  463.    object_list_append(_shapes, obj);
  464. }
  465.  
  466. ObjectList_t*
  467. get_shapes(void)
  468. {
  469.    return _shapes;
  470. }
  471.  
  472. void
  473. update_shape(Object_t *obj)
  474. {
  475.    object_list_update(_shapes, obj);
  476. }
  477.  
  478. static void
  479. edit_selected_shape(void)
  480. {
  481.    object_list_edit_selected(_shapes);
  482. }
  483.  
  484. void
  485. do_popup_menu(GdkEventButton *event)
  486. {
  487.    gint x = GET_REAL_COORD((gint) event->x);
  488.    gint y = GET_REAL_COORD((gint) event->y);
  489.    Object_t *obj = object_list_find(_shapes, x, y);
  490.    if (obj) {
  491.       obj->class->do_popup(obj, event);
  492.    } else {
  493.       do_main_popup_menu(event);
  494.    }
  495. }
  496.  
  497. static void
  498. set_all_sensitivities(void)
  499. {
  500.    gint count = object_list_nr_selected(_shapes);
  501.    menu_shapes_selected(count);
  502.    toolbar_shapes_selected(_toolbar, count);
  503.    tools_set_sensitive(count);
  504. }
  505.  
  506. static void
  507. main_set_title(const char *filename)
  508. {
  509.    char *title, *p;
  510.    
  511.    g_strreplace(&_filename, filename);
  512.    p = (filename) ? g_basename(filename) : _("<Untitled>");
  513.    title = g_strdup_printf("%s - ImageMap 1.4", p);
  514.    gtk_window_set_title(GTK_WINDOW(_dlg), title);
  515.    g_free(title);
  516. }
  517.  
  518. void 
  519. main_set_dimension(gint width, gint height)
  520. {
  521.    statusbar_set_dimension(_statusbar, width / _zoom_factor, 
  522.                height / _zoom_factor);
  523. }
  524.  
  525. void
  526. main_clear_dimension(void)
  527. {
  528.    statusbar_clear_dimension(_statusbar);
  529. }
  530.  
  531. void
  532. show_url(void)
  533. {
  534.    _show_url = TRUE;
  535. }
  536.  
  537. void
  538. hide_url(void)
  539. {
  540.    _show_url = FALSE;
  541.    statusbar_clear_status(_statusbar);
  542. }
  543.  
  544. void 
  545. select_shape(GtkWidget *widget, GdkEventButton *event)
  546. {
  547.    Object_t *obj;
  548.    gint x = GET_REAL_COORD((gint) event->x);
  549.    gint y = GET_REAL_COORD((gint) event->y);
  550.    MoveSashFunc_t sash_func;
  551.  
  552.    obj = object_list_near_sash(_shapes, x, y, &sash_func);
  553.    if (obj) {            /* Start resizing */
  554.       Command_t *command = move_sash_command_new(widget, obj, x, y, sash_func);
  555.       command_execute(command);
  556.    } else {
  557.       Command_t *command;
  558.  
  559.       obj = object_list_find(_shapes, x, y);
  560.       if (obj) {
  561.      if (event->state & GDK_SHIFT_MASK) {
  562.         if (obj->selected)
  563.            command = unselect_command_new(obj);
  564.         else
  565.            command = select_command_new(obj);
  566.      } else {        /* No Shift key pressed */
  567.         if (obj->selected) {
  568.            command = unselect_all_command_new(_shapes, obj);
  569.         } else {
  570.            Command_t *sub_command;
  571.  
  572.            command = subcommand_start(NULL);
  573.            sub_command = unselect_all_command_new(_shapes, NULL);
  574.            command_add_subcommand(command, sub_command);
  575.            sub_command = select_command_new(obj);
  576.            command_add_subcommand(command, sub_command);
  577.            command_set_name(command, sub_command->name);
  578.            subcommand_end();
  579.         }
  580.      }
  581.      command_execute(command);
  582.  
  583.      command = move_command_new(_preview, obj, x, y);
  584.      command_execute(command);
  585.       } else { /* Start selection rectangle */
  586.      command = select_region_command_new(widget, _shapes, x, y);
  587.      command_execute(command);
  588.       }
  589.    }
  590. }
  591.  
  592. void
  593. edit_shape(gint x, gint y)
  594. {
  595.    Object_t *obj;
  596.  
  597.    x = GET_REAL_COORD(x);
  598.    y = GET_REAL_COORD(y);
  599.  
  600.    obj = object_list_find(_shapes, x, y);
  601.    if (obj) {
  602.       object_select(obj);
  603.       object_edit(obj, TRUE);
  604.    }
  605. }
  606.  
  607. static void
  608. toolbar_grid(void)
  609. {
  610.    gint grid = toggle_grid();
  611.    popup_check_grid(grid);
  612.    menu_check_grid(grid);
  613. }
  614.  
  615. static void
  616. menu_zoom_in(void)
  617. {
  618.    gint factor = zoom_in();
  619.    menu_set_zoom_sensitivity(factor);
  620.    popup_set_zoom_sensitivity(factor);
  621. }
  622.  
  623. static void
  624. menu_zoom_out(void)
  625. {
  626.    gint factor = zoom_out();
  627.    menu_set_zoom_sensitivity(factor);
  628.    popup_set_zoom_sensitivity(factor);
  629. }
  630.  
  631. void 
  632. draw_shapes(GtkWidget *preview)
  633. {
  634.    if (!_preview_redraw_blocked)
  635.       object_list_draw(_shapes, preview->window);
  636. }
  637.  
  638. static void
  639. clear_map_info(void)
  640. {
  641.    gchar *author = g_get_real_name();
  642.  
  643.    if (!*author)
  644.       author = g_get_user_name();
  645.    g_strreplace(&_map_info.image_name, _image_name);
  646.    g_strreplace(&_map_info.title, "map");
  647.    g_strreplace(&_map_info.author, author);
  648.    g_strreplace(&_map_info.default_url, "");
  649.    g_strreplace(&_map_info.description, "");
  650.  
  651.    _map_info.map_format = CSIM;
  652.    _map_info.show_gray = FALSE;
  653. }
  654.  
  655. static void
  656. do_data_changed_dialog(void (*continue_cb)(gpointer), gpointer param)
  657. {
  658.    static DefaultDialog_t *dialog;
  659.  
  660.    if (!dialog) {
  661.       dialog = make_default_dialog(_("Data changed"));
  662.       default_dialog_hide_apply_button(dialog);
  663.       default_dialog_set_label(
  664.      dialog,
  665.      _("Some data has been changed.\n"
  666.        "Do you really want to discard your changes?"));
  667.    }
  668.    default_dialog_set_ok_cb(dialog, continue_cb, param);
  669.    default_dialog_show(dialog);
  670. }
  671.  
  672. static void
  673. check_if_changed(void (*func)(gpointer), gpointer param)
  674. {
  675.    if (object_list_get_changed(_shapes))
  676.       do_data_changed_dialog(func, param);
  677.    else
  678.       func(param);
  679. }
  680.  
  681. static void
  682. close_current(void)
  683. {
  684.    selection_freeze(_selection);
  685.    object_list_remove_all(_shapes);
  686.    selection_thaw(_selection);
  687.    clear_map_info();
  688.    main_set_title(NULL);
  689.    set_all_sensitivities();
  690.    redraw_preview();
  691.    object_list_clear_changed(_shapes);
  692.    command_list_remove_all();
  693. }
  694.  
  695. static void
  696. really_close(gpointer data)
  697. {
  698.    close_current();
  699. }
  700.  
  701. static void
  702. do_close(void)
  703. {
  704.    check_if_changed(really_close, NULL);
  705. }
  706.  
  707. static void
  708. really_quit(gpointer data)
  709. {
  710.    preferences_save(&_preferences);
  711.    run_flag = 1;
  712.    gtk_widget_destroy(_dlg);
  713. }
  714.  
  715. static void
  716. do_quit(void)
  717. {
  718.    check_if_changed(really_quit, NULL);
  719. }
  720.  
  721. static void
  722. do_undo(void)
  723. {
  724.    preview_freeze();
  725.    selection_freeze(_selection);
  726.    last_command_undo();
  727.    selection_thaw(_selection);
  728.    preview_thaw();
  729. }
  730.  
  731. static void
  732. do_redo(void)
  733. {
  734.    preview_freeze();
  735.    selection_freeze(_selection);
  736.    last_command_redo();
  737.    selection_thaw(_selection);
  738.    preview_thaw();
  739. }
  740.  
  741. static void
  742. save(void)
  743. {
  744.    if (_filename)
  745.       save_as(_filename);
  746.    else
  747.       do_file_save_as_dialog();
  748. }
  749.  
  750. static void
  751. write_cern_comment(gpointer param, OutputFunc_t output)
  752. {
  753.    output(param, "rect (4096,4096) (4096,4096) imap:#$");   
  754. }
  755.  
  756. static void
  757. save_as_cern(gpointer param, OutputFunc_t output)
  758. {
  759.    char *p;
  760.    gchar *description;
  761.    gchar *next_token;
  762.  
  763.    write_cern_comment(param, output);
  764.    output(param, "-:Image Map file created by GIMP Imagemap Plugin\n");
  765.    write_cern_comment(param, output);
  766.    output(param, "-:GIMP Imagemap Plugin by Maurits Rijk\n");
  767.    write_cern_comment(param, output);
  768.    output(param, "-:Please do not edit lines starting with \"#$\"\n");
  769.    write_cern_comment(param, output);
  770.    output(param, "VERSION:1.4\n");
  771.    write_cern_comment(param, output);
  772.    output(param, "TITLE:%s\n", _map_info.title);
  773.    write_cern_comment(param, output);
  774.    output(param, "AUTHOR:%s\n", _map_info.author);
  775.    write_cern_comment(param, output);
  776.    output(param, "FORMAT:cern\n");
  777.    
  778.    description = g_strdup(_map_info.description);
  779.    next_token = description;
  780.    for (p = strtok (next_token, "\n"); p; p = strtok(NULL, "\n")) {
  781.       write_cern_comment(param, output);
  782.       output(param, "DESCRIPTION:%s\n", p);
  783.    }
  784.    g_free(description);
  785.  
  786.    if (*_map_info.default_url)
  787.       output(param, "default %s\n", _map_info.default_url);
  788.    object_list_write_cern(_shapes, param, output);
  789. }
  790.  
  791. static void
  792. save_as_csim(gpointer param, OutputFunc_t output)
  793. {
  794.    char *p;
  795.    gchar *description;
  796.    
  797.    output(param, "<img src=\"%s\" width=\"%d\" height=\"%d\" border=\"0\" "
  798.       "usemap=\"#%s\" />\n\n", _map_info.image_name,
  799.       _image_width, _image_height, _map_info.title);
  800.    output(param, "<map name=\"%s\">\n", _map_info.title);
  801.    output(param, 
  802.       "<!-- #$-:Image Map file created by GIMP Imagemap Plugin -->\n");
  803.    output(param, "<!-- #$-:GIMP Imagemap Plugin by Maurits Rijk -->\n");
  804.    output(param, 
  805.       "<!-- #$-:Please do not edit lines starting with \"#$\" -->\n");
  806.    output(param, "<!-- #$VERSION:1.4 -->\n");
  807.    output(param, "<!-- #$AUTHOR:%s -->\n", _map_info.author);
  808.    
  809.    description = g_strdup(_map_info.description);
  810.    for (p = strtok(description, "\n"); p; p = strtok(NULL, "\n"))
  811.       output(param, "<!-- #$DESCRIPTION:%s -->\n", p);
  812.    g_free(description);
  813.    
  814.    object_list_write_csim(_shapes, param, output);
  815.    if (*_map_info.default_url)
  816.       output(param, "<area shape=\"default\" href=\"%s\" />\n",
  817.          _map_info.default_url);
  818.    output(param, "</map>\n");
  819. }
  820.  
  821. static void
  822. save_as_ncsa(gpointer param, OutputFunc_t output)
  823. {
  824.    char *p;
  825.    gchar *description;
  826.  
  827.    output(param, "#$-:Image Map file created by GIMP Imagemap Plugin\n");
  828.    output(param, "#$-:GIMP Imagemap Plugin by Maurits Rijk\n");
  829.    output(param, "#$-:Please do not edit lines starting with \"#$\"\n");
  830.    output(param, "#$VERSION:1.4\n");
  831.    output(param, "#$TITLE:%s\n", _map_info.title);
  832.    output(param, "#$AUTHOR:%s\n", _map_info.author);
  833.    output(param, "#$FORMAT:ncsa\n");
  834.    
  835.    description = g_strdup(_map_info.description);
  836.    for (p = strtok(description, "\n"); p; p = strtok(NULL, "\n"))
  837.       output(param, "#$DESCRIPTION:%s\n", p);
  838.    g_free(description);
  839.  
  840.    if (*_map_info.default_url)
  841.       output(param, "default %s\n", _map_info.default_url);
  842.    object_list_write_ncsa(_shapes, param, output);
  843. }
  844.  
  845. static void 
  846. save_to_file(gpointer param, const char* format, ...)
  847. {
  848.    va_list ap;
  849.  
  850.    va_start(ap, format);
  851.    vfprintf((FILE*)param, format, ap);
  852.    va_end(ap);
  853. }
  854.  
  855. void
  856. dump_output(gpointer param, OutputFunc_t output)
  857. {
  858.    if (_map_info.map_format == NCSA)
  859.       save_as_ncsa(param, output);
  860.    else if (_map_info.map_format == CERN)
  861.       save_as_cern(param, output);
  862.    else if (_map_info.map_format == CSIM)
  863.       save_as_csim(param, output);
  864. }
  865.  
  866. void
  867. save_as(const gchar *filename)
  868. {
  869.    FILE *out = fopen(filename, "w");
  870.    if (out) {
  871.       dump_output(out, save_to_file);
  872.       fclose(out);
  873.  
  874.       statusbar_set_status(_statusbar, _("File \"%s\" saved."), filename);
  875.       main_set_title(filename);
  876.       object_list_clear_changed(_shapes);
  877.    } else {
  878.       do_file_error_dialog( _("Couldn't save file:"), filename);
  879.    }
  880. }
  881.  
  882. static void
  883. resize_image_ok_cb(gpointer data)
  884. {
  885.    gint per_x = _image_width * 100 / _map_info.old_image_width;
  886.    gint per_y = _image_height * 100 / _map_info.old_image_height;
  887.    object_list_resize(_shapes, per_x, per_y);
  888.    preview_thaw();
  889. }
  890.  
  891. static void
  892. resize_image_cancel_cb(gpointer data)
  893. {
  894.    preview_thaw();
  895. }
  896.  
  897. static void
  898. do_image_size_changed_dialog(void)
  899. {
  900.    static DefaultDialog_t *dialog;
  901.  
  902.    if (!dialog) {
  903.       dialog = make_default_dialog( _("Image size changed"));
  904.       default_dialog_hide_apply_button(dialog);
  905.       default_dialog_set_label(
  906.      dialog,
  907.      _("Image size has changed.\n"
  908.        "Resize Area's?"));
  909.  
  910.       default_dialog_set_ok_cb(dialog, resize_image_ok_cb, NULL);
  911.       default_dialog_set_cancel_cb(dialog, resize_image_cancel_cb, NULL);
  912.    }
  913.    default_dialog_show(dialog);
  914.  
  915. }
  916.  
  917. static void
  918. really_load(gpointer data)
  919. {
  920.    gchar *filename = (gchar*) data;
  921.    close_current();
  922.  
  923.    selection_freeze(_selection);
  924.    _map_info.old_image_width = _image_width;
  925.    _map_info.old_image_height = _image_height;
  926.    if (load_csim(filename)) {
  927.       _map_info.map_format = CSIM;
  928.       if (_image_width != _map_info.old_image_width ||
  929.       _image_height != _map_info.old_image_height) {
  930.      preview_freeze();
  931.      do_image_size_changed_dialog();
  932.       }
  933.    } else if (load_ncsa(filename)) {
  934.       _map_info.map_format = NCSA;
  935.    } else if (load_cern(filename)) {
  936.       _map_info.map_format = CERN;
  937.    } else {
  938.       do_file_error_dialog( _("Couldn't read file:"), filename);
  939.       selection_thaw(_selection);
  940.       close_current();
  941.       return;
  942.    }
  943.    mru_set_first(_mru, filename);
  944.    menu_build_mru_items(_mru);
  945.  
  946.    selection_thaw(_selection);
  947.    main_set_title(filename);
  948.    object_list_clear_changed(_shapes);
  949.    redraw_preview();
  950. }
  951.  
  952. void
  953. load(const gchar *filename)
  954. {
  955.    static gchar *tmp_filename;
  956.    g_strreplace(&tmp_filename, filename);
  957.    check_if_changed(really_load, (gpointer) tmp_filename);
  958. }
  959.  
  960. static void 
  961. toggle_area_list(void)
  962. {
  963.    selection_toggle_visibility(_selection);
  964. }
  965.  
  966. static void
  967. close_callback(GtkWidget *widget, gpointer data)
  968. {
  969.    gtk_main_quit();
  970. }
  971.  
  972. static void
  973. preview_move(GtkWidget *widget, GdkEventMotion *event)
  974. {
  975.    gint x = GET_REAL_COORD((gint) event->x);
  976.    gint y = GET_REAL_COORD((gint) event->y);
  977.    static Object_t *prev_obj = NULL;
  978.    Object_t *obj = object_list_find(_shapes, x, y);
  979.  
  980.    statusbar_set_xy(_statusbar, x, y);
  981.    if (obj != prev_obj) {
  982.       prev_obj = obj;
  983.       if (obj && _show_url) {
  984.      statusbar_set_status(_statusbar, _("URL: %s"), obj->url);
  985.       } else {
  986.      statusbar_clear_status(_statusbar);
  987.       }
  988.    }
  989. #ifdef _NOT_READY_YET_
  990.    if (!obj) {
  991.       if (grid_near_x(x)) {
  992.      preview_set_cursor(_preview, GDK_SB_H_DOUBLE_ARROW);
  993.       } else if (grid_near_y(y)) {
  994.      preview_set_cursor(_preview, GDK_SB_V_DOUBLE_ARROW);
  995.       } else {
  996.      preview_set_cursor(_preview, _cursor);
  997.       }
  998.    }
  999. #endif
  1000. }
  1001.  
  1002. static void
  1003. preview_enter(GtkWidget *widget, GdkEventCrossing *event)
  1004. {
  1005.    preview_set_cursor(_preview, _cursor);
  1006. }
  1007.  
  1008. static void
  1009. preview_leave(GtkWidget *widget, GdkEventCrossing *event)
  1010. {
  1011.    gdk_window_set_cursor(_dlg->window, NULL);
  1012.    statusbar_clear_xy(_statusbar);
  1013. }
  1014.  
  1015. static void 
  1016. button_press(GtkWidget* widget, GdkEventButton* event, gpointer data)
  1017. {
  1018.    _button_press_func(widget, event, _button_press_param);
  1019. }
  1020.  
  1021. /* A few global vars for key movement */
  1022.  
  1023. static gint _timeout;
  1024. static guint _keyval;
  1025. static gint _dx, _dy;
  1026.  
  1027. static void
  1028. move_selected_objects(gint dx, gint dy, gboolean fast)
  1029. {
  1030.    if (fast) {
  1031.       dx *= 5;
  1032.       dy *= 5;
  1033.    }
  1034.    _dx += dx;
  1035.    _dy += dy;
  1036.  
  1037.    gdk_gc_set_function(_preferences.normal_gc, GDK_EQUIV);
  1038.    gdk_gc_set_function(_preferences.selected_gc, GDK_EQUIV);
  1039.    object_list_draw_selected(_shapes, _preview->preview->window);
  1040.    object_list_move_selected(_shapes, dx, dy);
  1041.    object_list_draw_selected(_shapes, _preview->preview->window);
  1042.    gdk_gc_set_function(_preferences.normal_gc, GDK_COPY);
  1043.    gdk_gc_set_function(_preferences.selected_gc, GDK_COPY);
  1044. }
  1045.  
  1046. static gboolean
  1047. key_timeout_cb(gpointer data)
  1048. {
  1049.    switch (_keyval) {
  1050.    case GDK_Left:
  1051.    case GDK_Right:
  1052.    case GDK_Up:
  1053.    case GDK_Down:
  1054.       command_list_add(move_selected_command_new(_shapes, _dx, _dy));
  1055.       _dx = _dy = 0;
  1056.       break;
  1057.    }
  1058.    preview_thaw();
  1059.    return FALSE;
  1060. }
  1061.  
  1062. static gboolean 
  1063. key_press_cb(GtkWidget *widget, GdkEventKey *event)
  1064. {
  1065.    gint handled = FALSE;
  1066.    gboolean shift = event->state & GDK_SHIFT_MASK;
  1067.    Command_t *command;
  1068.  
  1069.    preview_freeze();
  1070.    if (_timeout)
  1071.       gtk_timeout_remove(_timeout);
  1072.  
  1073.    switch (event->keyval) {
  1074.    case GDK_Left:
  1075.       move_selected_objects(-1, 0, shift);
  1076.       handled = TRUE;
  1077.       break;
  1078.    case GDK_Right:
  1079.       move_selected_objects(1, 0, shift);
  1080.       handled = TRUE;
  1081.       break;
  1082.    case GDK_Up:
  1083.       move_selected_objects(0, -1, shift);
  1084.       handled = TRUE;
  1085.       break;
  1086.    case GDK_Down:
  1087.       move_selected_objects(0, 1, shift);
  1088.       handled = TRUE;
  1089.       break;
  1090.    case GDK_Tab:
  1091.       if (shift)
  1092.      command = select_prev_command_new(_shapes);
  1093.       else
  1094.      command = select_next_command_new(_shapes);
  1095.       command_execute(command);
  1096.       handled = TRUE;
  1097.       break;
  1098.    }
  1099.    if (handled)
  1100.       gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "key_press_event");
  1101.  
  1102.    return handled;
  1103. }
  1104.  
  1105. static gboolean 
  1106. key_release_cb(GtkWidget *widget, GdkEventKey *event)
  1107. {
  1108.    _keyval = event->keyval;
  1109.    _timeout = gtk_timeout_add(250, key_timeout_cb, NULL);
  1110.    return FALSE;
  1111. }
  1112.  
  1113. static void
  1114. geometry_changed(Object_t *obj, gpointer data)
  1115. {
  1116.    redraw_preview();        /* Fix me! */
  1117. }
  1118.  
  1119. static void
  1120. data_changed(Object_t *obj, gpointer data)
  1121. {
  1122.    set_all_sensitivities();
  1123. }
  1124.  
  1125. static void
  1126. data_selected(Object_t *obj, gpointer data)
  1127. {
  1128.    set_all_sensitivities();
  1129. }
  1130.  
  1131. static Command_t*
  1132. factory_file_open_dialog(void)
  1133. {
  1134.    return command_new(do_file_open_dialog);
  1135. }
  1136.  
  1137. static Command_t*
  1138. factory_save(void)
  1139. {
  1140.    return command_new(save);
  1141. }
  1142.  
  1143. static Command_t*
  1144. factory_save_as(void)
  1145. {
  1146.    return command_new(do_file_save_as_dialog);
  1147. }
  1148.  
  1149. static Command_t*
  1150. factory_preferences_dialog(void)
  1151. {
  1152.    return command_new(do_preferences_dialog);
  1153. }
  1154.  
  1155. static Command_t*
  1156. factory_close(void)
  1157. {
  1158.    return command_new(do_close);
  1159. }
  1160.  
  1161. static Command_t*
  1162. factory_quit(void)
  1163. {
  1164.    return command_new(do_quit);
  1165. }
  1166.  
  1167.  
  1168. static Command_t*
  1169. factory_undo(void)
  1170. {
  1171.    return command_new(do_undo);
  1172. }
  1173.  
  1174. static Command_t*
  1175. factory_redo(void)
  1176. {
  1177.    return command_new(do_redo);
  1178. }
  1179.  
  1180. static Command_t*
  1181. factory_cut(void)
  1182. {
  1183.    return cut_command_new(_shapes);
  1184. }
  1185.  
  1186. static Command_t*
  1187. factory_copy(void)
  1188. {
  1189.    return copy_command_new(_shapes);
  1190. }
  1191.  
  1192. static Command_t*
  1193. factory_paste(void)
  1194. {
  1195.    return paste_command_new(_shapes);
  1196. }
  1197.  
  1198. static Command_t*
  1199. factory_select_all(void)
  1200. {
  1201.    return select_all_command_new(_shapes);
  1202. }
  1203.  
  1204. static Command_t*
  1205. factory_clear(void)
  1206. {
  1207.    return clear_command_new(_shapes);
  1208. }
  1209.  
  1210. static Command_t*
  1211. factory_edit(void)
  1212. {
  1213.    return command_new(edit_selected_shape);
  1214. }
  1215.  
  1216. static Command_t*
  1217. factory_toggle_area_list(void)
  1218. {
  1219.    return command_new(toggle_area_list);
  1220. }
  1221.  
  1222. static Command_t*
  1223. factory_source_dialog(void)
  1224. {
  1225.    return command_new(do_source_dialog);
  1226. }
  1227.  
  1228. static Command_t*
  1229. factory_preview_color(void)
  1230. {
  1231.    return command_new(set_preview_color);
  1232. }
  1233.  
  1234. static Command_t*
  1235. factory_preview_gray(void)
  1236. {
  1237.    return command_new(set_preview_gray);
  1238. }
  1239.  
  1240. static Command_t*
  1241. factory_menu_zoom_in(void)
  1242. {
  1243.    return command_new(menu_zoom_in);
  1244. }
  1245.  
  1246. static Command_t*
  1247. factory_menu_zoom_out(void)
  1248. {
  1249.    return command_new(menu_zoom_out);
  1250. }
  1251.  
  1252. static Command_t*
  1253. factory_zoom_in(void)
  1254. {
  1255.    return command_new((void (*)(void)) zoom_in);
  1256. }
  1257.  
  1258. static Command_t*
  1259. factory_zoom_out(void)
  1260. {
  1261.    return command_new((void (*)(void)) zoom_out);
  1262. }
  1263.  
  1264. static Command_t*
  1265. factory_settings_dialog(void)
  1266. {
  1267.    return command_new(do_settings_dialog);
  1268. }
  1269.  
  1270. static Command_t*
  1271. factory_move_to_front(void)
  1272. {
  1273.    return move_to_front_command_new(_shapes);
  1274. }
  1275.  
  1276. static Command_t*
  1277. factory_send_to_back(void)
  1278. {
  1279.    return send_to_back_command_new(_shapes);
  1280. }
  1281.  
  1282. static Command_t*
  1283. factory_toolbar_grid(void)
  1284. {
  1285.    return command_new(toolbar_grid);
  1286. }
  1287.  
  1288. static Command_t*
  1289. factory_grid_settings_dialog(void)
  1290. {
  1291.    return command_new(do_grid_settings_dialog);
  1292. }
  1293.  
  1294. static Command_t*
  1295. factory_create_guides_dialog(void)
  1296. {
  1297.    return guides_command_new(_shapes);
  1298. }
  1299.  
  1300. static Command_t*
  1301. factory_about_dialog(void)
  1302. {
  1303.    return command_new(do_about_dialog);
  1304. }
  1305.  
  1306. static Command_t*
  1307. factory_move_up(void)
  1308. {
  1309.    return move_up_command_new(_shapes);
  1310. }
  1311.  
  1312. static Command_t*
  1313. factory_move_down(void)
  1314. {
  1315.    return move_down_command_new(_shapes);
  1316. }
  1317.  
  1318. static gint
  1319. dialog(GimpDrawable *drawable)
  1320. {
  1321.    GtkWidget     *dlg;
  1322.    GtkWidget     *hbox;
  1323.    GtkWidget     *main_vbox;
  1324.    Tools_t    *tools;
  1325.    Menu_t    *menu;
  1326.    PopupMenu_t  *popup;
  1327.  
  1328.    gimp_ui_init ("imagemap", TRUE);
  1329.  
  1330.    _shapes = make_object_list();
  1331.  
  1332.    _dlg = dlg = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  1333.    gtk_window_set_policy(GTK_WINDOW(dlg), TRUE, TRUE, FALSE);
  1334.    gtk_widget_realize(dlg);
  1335.  
  1336.    main_set_title(NULL);
  1337.    gimp_help_connect_help_accel (dlg, gimp_standard_help_func, "filters/imagemap.html");
  1338.  
  1339.    gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_MOUSE);
  1340.    gtk_signal_connect(GTK_OBJECT(dlg), "destroy",
  1341.               (GtkSignalFunc) close_callback, NULL);
  1342.    gtk_signal_connect(GTK_OBJECT(dlg), "key_press_event", 
  1343.               (GtkSignalFunc) key_press_cb, NULL);
  1344.    gtk_signal_connect(GTK_OBJECT(dlg), "key_release_event", 
  1345.               (GtkSignalFunc) key_release_cb, NULL);
  1346.  
  1347.    main_vbox = gtk_vbox_new(FALSE, 1);
  1348.    gtk_container_set_border_width(GTK_CONTAINER(main_vbox), 1);
  1349.    gtk_container_add(GTK_CONTAINER(dlg), main_vbox);
  1350.    gtk_widget_show(main_vbox);
  1351.  
  1352.    /* Create menu */
  1353.    menu = make_menu(main_vbox, dlg);
  1354.    menu_set_open_command(menu, factory_file_open_dialog);
  1355.    menu_set_save_command(menu, factory_save);
  1356.    menu_set_save_as_command(menu, factory_save_as);
  1357.    menu_set_preferences_command(menu, factory_preferences_dialog);
  1358.    menu_set_close_command(menu, factory_close);
  1359.    menu_set_quit_command(menu, factory_quit);
  1360.    menu_set_undo_command(menu, factory_undo);
  1361.    menu_set_redo_command(menu, factory_redo);
  1362.    menu_set_cut_command(menu, factory_cut);
  1363.    menu_set_copy_command(menu, factory_copy);
  1364.    menu_set_paste_command(menu, factory_paste);
  1365.    menu_set_select_all_command(menu, factory_select_all);
  1366.    menu_set_clear_command(menu, factory_clear);
  1367.    menu_set_edit_erea_info_command(menu, factory_edit);
  1368.    menu_set_area_list_command(menu, factory_toggle_area_list);
  1369.    menu_set_source_command(menu, factory_source_dialog);
  1370.    menu_set_color_command(menu, factory_preview_color);
  1371.    menu_set_gray_command(menu, factory_preview_gray);
  1372.    menu_set_zoom_in_command(menu, factory_menu_zoom_in);
  1373.    menu_set_zoom_out_command(menu, factory_menu_zoom_out);
  1374.    menu_set_edit_map_info_command(menu, factory_settings_dialog);
  1375.    menu_set_grid_settings_command(menu, factory_grid_settings_dialog);
  1376.    menu_set_create_guides_command(menu, factory_create_guides_dialog);
  1377.    menu_set_about_command(menu, factory_about_dialog);
  1378.  
  1379.    /* Create popup */
  1380.    popup = create_main_popup_menu();
  1381.    popup_set_zoom_in_command(popup, factory_zoom_in);
  1382.    popup_set_zoom_out_command(popup, factory_zoom_out);
  1383.    popup_set_edit_map_info_command(popup, factory_settings_dialog);
  1384.    popup_set_grid_settings_command(popup, factory_grid_settings_dialog);
  1385.    popup_set_create_guides_command(popup, factory_create_guides_dialog);
  1386.    popup_set_paste_command(popup, factory_paste);
  1387.  
  1388.    /* Create toolbar */
  1389.    _toolbar = make_toolbar(main_vbox, dlg);
  1390.    toolbar_set_open_command(_toolbar, factory_file_open_dialog);
  1391.    toolbar_set_save_command(_toolbar, factory_save);
  1392.    toolbar_set_preferences_command(_toolbar, factory_preferences_dialog);
  1393.    toolbar_set_undo_command(_toolbar, factory_undo);
  1394.    toolbar_set_redo_command(_toolbar, factory_redo);
  1395.    toolbar_set_cut_command(_toolbar, factory_cut);
  1396.    toolbar_set_copy_command(_toolbar, factory_copy);
  1397.    toolbar_set_paste_command(_toolbar, factory_paste);
  1398.    toolbar_set_zoom_in_command(_toolbar, factory_zoom_in);
  1399.    toolbar_set_zoom_out_command(_toolbar, factory_zoom_out);
  1400.    toolbar_set_edit_map_info_command(_toolbar, factory_settings_dialog);
  1401.    toolbar_set_move_to_front_command(_toolbar, factory_move_to_front);
  1402.    toolbar_set_send_to_back_command(_toolbar, factory_send_to_back);
  1403.    toolbar_set_grid_command(_toolbar, factory_toolbar_grid);
  1404.  
  1405.    /*  Dialog area  */
  1406.    hbox = gtk_hbox_new(FALSE, 1);
  1407.    gtk_container_add(GTK_CONTAINER(main_vbox), hbox);
  1408.    gtk_widget_show(hbox);
  1409.  
  1410.    tools = make_tools(dlg);
  1411.    selection_set_delete_command(tools, factory_clear);
  1412.    selection_set_edit_command(tools, factory_edit);
  1413.    gtk_box_pack_start(GTK_BOX(hbox), tools->container, FALSE, FALSE, 0);
  1414.  
  1415.    _preview = make_preview(drawable);
  1416.    add_preview_motion_event(_preview, (GtkSignalFunc) preview_move);
  1417.    add_enter_notify_event(_preview, (GtkSignalFunc) preview_enter);
  1418.    add_leave_notify_event(_preview, (GtkSignalFunc) preview_leave);
  1419.    add_preview_button_press_event(_preview, (GtkSignalFunc) button_press);
  1420.    gtk_container_add(GTK_CONTAINER(hbox), _preview->window);
  1421.  
  1422.    object_list_add_geometry_cb(_shapes, geometry_changed, NULL);
  1423.    object_list_add_update_cb(_shapes, data_changed, NULL);
  1424.    object_list_add_add_cb(_shapes, data_changed, NULL);
  1425.    object_list_add_remove_cb(_shapes, data_changed, NULL);
  1426.    object_list_add_move_cb(_shapes, data_changed, NULL);
  1427.    object_list_add_select_cb(_shapes, data_selected, NULL);
  1428.  
  1429.    /* Selection */
  1430.    _selection = make_selection(dlg, _shapes);
  1431.    selection_set_move_up_command(_selection, factory_move_up);
  1432.    selection_set_move_down_command(_selection, factory_move_down);
  1433.    selection_set_delete_command(_selection, factory_clear);
  1434.    selection_set_edit_command(_selection, factory_edit);
  1435.    gtk_box_pack_start(GTK_BOX(hbox), _selection->container, FALSE, FALSE, 0);
  1436.  
  1437.    _statusbar = make_statusbar(main_vbox, dlg);
  1438.    statusbar_set_zoom(_statusbar, 1);
  1439.  
  1440.    clear_map_info();
  1441.  
  1442.    gtk_widget_show(dlg);
  1443.  
  1444.    _mru = mru_create();
  1445.    init_preferences();
  1446.    if (!mru_empty(_mru))
  1447.       menu_build_mru_items(_mru);
  1448.  
  1449.    gtk_main();
  1450.    gdk_flush();
  1451.    
  1452.    return run_flag;
  1453. }
  1454.